package com.castle.fortress.admin.pay.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.castle.fortress.admin.pay.dto.*;
import com.castle.fortress.admin.pay.enums.PayTypeEnum;
import com.castle.fortress.admin.pay.service.PayService;
import com.castle.fortress.common.entity.RespBody;
import com.castle.fortress.common.exception.BizException;
import com.castle.fortress.common.respcode.BizErrorCode;
import com.castle.fortress.common.respcode.GlobalRespCode;
import com.castle.fortress.common.utils.CommonUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;


/**
 * 支付宝支付
 * @@author castle
 */

public class AliPayClient implements PayService {
    private PayAliConfigDto configDto;
    private AlipayClient alipayClient;

    public AliPayClient(PayAliConfigDto configDto){
        this.configDto=configDto;
        //实例化客户端
        this.alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", configDto.getAppId(), configDto.getPrivateKey(), "json", "utf-8", configDto.getAliPayPublicKey(), "RSA2");
    }

    @Override
    public RespBody<PayResponse> uniorder(PayRequest request) {
        if(CommonUtil.verifyParamNull(request,request.getOrderId(),request.getOrderAmount())){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        JSONObject bizContent = new JSONObject();
        bizContent.set("out_trade_no", request.getOrderId());
        bizContent.set("total_amount", request.getOrderAmount().toString());
        bizContent.set("subject", StrUtil.isEmpty(request.getOrderName()) ? request.getOrderId(): request.getOrderName());
        String body="",tradeNo="";
        PayResponse response=buildPayResponse(request);
        try {
            //APP支付
            if(PayTypeEnum.ALIPAY_APP.getCode().equals(this.configDto.getPayTypeCode())) {
                //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
                AlipayTradeAppPayRequest payRequest = new AlipayTradeAppPayRequest();
                payRequest.setNotifyUrl(this.configDto.getNotifyUrl());
                payRequest.setBizContent(bizContent.toString());
                //这里和普通的接口调用不同，使用的是sdkExecute
                AlipayTradeAppPayResponse payResponse = alipayClient.sdkExecute(payRequest);
                if (!payResponse.isSuccess()) {
                    throw new BizException(BizErrorCode.PAY_UNIORDER_ALI_ERROR, payResponse.getMsg());
                }
                body = payResponse.getBody();
                tradeNo = payResponse.getTradeNo();
                System.out.println(body);//就是orderString 可以直接给客户端请求，无需再做处理。
            //小程序支付
            }else if(PayTypeEnum.ALIPAY_MINI.getCode().equals(this.configDto.getPayTypeCode())){
                AlipayTradeCreateRequest payRequest = new AlipayTradeCreateRequest();
                payRequest.setNotifyUrl(this.configDto.getNotifyUrl());
                bizContent.set("buyer_id", request.getBuyerId());
                payRequest.setBizContent(bizContent.toString());
                AlipayTradeCreateResponse payResponse = alipayClient.execute(payRequest);
                if (!payResponse.isSuccess()) {
                    throw new BizException(BizErrorCode.PAY_UNIORDER_ALI_ERROR, payResponse.getMsg());
                }
                body = payResponse.getBody();
                tradeNo = payResponse.getTradeNo();
                System.out.println(body);//就是orderString 可以直接给客户端请求，无需再做处理。
            //手机网站支付
            }else if(PayTypeEnum.ALIPAY_WAP.getCode().equals(this.configDto.getPayTypeCode())){
                AlipayTradeWapPayRequest payRequest = new AlipayTradeWapPayRequest();
                payRequest.setNotifyUrl(this.configDto.getNotifyUrl());
                bizContent.set("product_code","QUICK_WAP_WAY");
                //用户付款中途退出返回商户网站的地址
                bizContent.set("quit_url",request.getQuitUrl());
                payRequest.setBizContent(bizContent.toString());
                AlipayTradeWapPayResponse payResponse = alipayClient.pageExecute(payRequest);
                if (!payResponse.isSuccess()) {
                    throw new BizException(BizErrorCode.PAY_UNIORDER_ALI_ERROR, payResponse.getMsg());
                }
                body = payResponse.getBody();
                //就是orderString 可以直接给客户端请求，无需再做处理。
                tradeNo = payResponse.getTradeNo();
            //电脑网站支付
            }else if(PayTypeEnum.ALIPAY_PC.getCode().equals(this.configDto.getPayTypeCode())){
                AlipayTradePagePayRequest payRequest = new AlipayTradePagePayRequest();
                payRequest.setNotifyUrl(this.configDto.getNotifyUrl());
                bizContent.set("product_code", "FAST_INSTANT_TRADE_PAY");
                payRequest.setBizContent(bizContent.toString());
                System.out.println(payRequest);
                AlipayTradePagePayResponse payResponse = alipayClient.pageExecute(payRequest);
                if (!payResponse.isSuccess()) {
                    throw new BizException(BizErrorCode.PAY_UNIORDER_ALI_ERROR, payResponse.getMsg());
                }
                //就是orderString 可以直接给客户端请求，无需再做处理。
                body = payResponse.getBody();
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new BizException(BizErrorCode.PAY_UNIORDER_ALI_ERROR);
        }
        response.setBody(body);
        response.setTradeNo(tradeNo);
        return RespBody.data(response);
    }

    @Override
    public RespBody<PayResponse> asyncNotify(HttpServletRequest request, String notifyData, PayTypeEnum payType, String sceneCode) {
        Map< String , String > params = new HashMap < String , String > ();
        Map requestParams = request.getParameterMap();
        for(Iterator iter = requestParams.keySet().iterator();iter.hasNext();){
            String name = (String)iter.next();
            String[] values = (String [])requestParams.get(name);
            String valueStr = "";
            for(int i = 0;i < values.length;i ++ ){
                valueStr =  (i==values.length-1)?valueStr + values [i]:valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put (name,valueStr);
        }
        PayResponse response= new PayResponse();
        try {
            if(checkData(params)){
                response.setOrderId(params.get("out_trade_no"));
                response.setTradeNo(params.get("trade_no"));
                response.setOrderAmount(Double.valueOf(params.get("total_amount")));
                return RespBody.data(response);
            }else{
                return RespBody.fail(BizErrorCode.PAY_ASYNC_SIGN_VERIFY_FAIL);
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return RespBody.fail(BizErrorCode.PAY_ASYNC_SIGN_VERIFY_FAIL);
        }
    }

    /**
     * 验签及校验数据
     * @return
     */
    private boolean checkData(Map< String , String > params) throws AlipayApiException {

        //切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
        boolean flag = AlipaySignature.rsaCheckV1 (params,this.configDto.getAliPayPublicKey(), "utf-8","RSA2");
        if(flag){
            if(!params.get("app_id").equals(this.configDto.getAppId())){
            flag=false;
            }
        }
        System.out.println("checkData:"+flag);
        return flag;
    }

    @Override
    public RespBody<RefundResponse> refund(RefundRequest refundRequest) {
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.set("out_trade_no", refundRequest.getOrderId());
        bizContent.set("refund_amount", refundRequest.getRefundAmount());
        //退款请求号。
        //标识一次退款请求，需要保证在交易号下唯一，如需部分退款，则此参数必传。
        //注：针对同一次退款请求，如果调用接口失败或异常了，重试时需要保证退款请求号不能变更，防止该笔交易重复退款。支付宝会保证同样的退款请求号多次请求只会退一次。
        bizContent.set("out_request_no", refundRequest.getRefundNo());
        request.setBizContent(bizContent.toString());
        AlipayTradeRefundResponse response = null;
        String body="";
        try {
            response = alipayClient.execute(request);
            if (!response.isSuccess()) {
                throw new BizException(BizErrorCode.PAY_UNIORDER_ALI_ERROR, response.getMsg());
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        RefundResponse refundResponse = buildRefoundResponse(response);
        refundResponse.setOrderAmount(refundRequest.getOrderAmount());
        refundResponse.setRefundNo(refundRequest.getRefundNo());
        return RespBody.data(refundResponse);
    }

    private PayResponse buildPayResponse(PayRequest request){
        PayResponse response = new PayResponse();
        response.setAppId(this.configDto.getAppId());
        response.setAttach(request.getSceneCode());
        response.setOrderAmount(request.getOrderAmount());
        response.setOrderId(request.getOrderId());
        return response;
    }

    private RefundResponse buildRefoundResponse(AlipayTradeRefundResponse refundResponse){
        RefundResponse response = new RefundResponse();
        response.setOrderId(refundResponse.getOutTradeNo());
        response.setTradeNo(refundResponse.getTradeNo());
        response.setRefundFee(refundResponse.getRefundFee());
        response.setSendBackFee(refundResponse.getSendBackFee());
        response.setRefundDate(new Date());
        return response;

    }
}